
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import main.example.Link;
import org.java_websocket.WebSocket;
import org.java_websocket.WebSocketImpl;
import org.java_websocket.framing.Framedata;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

/**
 * A simple WebSocketServer implementation. Keeps track of a "chatroom".
 */
public class ChatServer extends WebSocketServer {

    private static ArrayList<Link> links = new ArrayList<Link>();

	public ChatServer( int port ) throws UnknownHostException {
		super( new InetSocketAddress( port ) );
	}

	public ChatServer( InetSocketAddress address ) {
		super(address);
	}

    @Override
	public void onOpen( WebSocket conn, ClientHandshake handshake ) {
		this.sendToAll( "new connection: " + handshake.getResourceDescriptor() );
		System.out.println( conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!" );
	}

	@Override
	public void onClose( WebSocket conn, int code, String reason, boolean remote ) {
		this.sendToAll( conn + " has left the room!" );
		/*System.out.println( conn + " has left the room!" );*/
        unLinkOne(conn);
    }

    public static List<Link> getUnLinks() {
        List<Link> result = new ArrayList<Link>();
        for (Link link: links) {
            if (!link.isConnect()) {
                result.add(link);
            }
        }
        return result;
    }

    private void unLinkOne(WebSocket conn) {
        Link linkByIp = findLinkByIp(conn.getRemoteSocketAddress().getAddress().getHostAddress());
        if (linkByIp != null) {
            linkByIp.setConnect(false);
        }
    }

    private Link findLinkByIp(String hostAddress) {
        for (Link link : links) {
            String ip = link.getIp();
            if (ip != null && ip.equals(hostAddress)) {
                return link;
            }
        }
        return null;
    }

    @Override
	public void onMessage( WebSocket conn, String message ) {
        linkOne(conn, message);
    }

    private void linkOne(WebSocket conn, String message) {
        String[] msg = message.split("_");
        String number = msg[msg.length - 1];
        int i = Integer.parseInt(number);
        Link linkByNumber = findLinkByNumber(i);
        if (linkByNumber != null){
            linkByNumber.setConnect(true);
            linkByNumber.setIp(conn.getRemoteSocketAddress().getAddress().getHostAddress());
        }
    }

    private Link findLinkByNumber(int number) {
        for (Link link: links) {
            if (link.getNumber() == number) {
                return link;
            }
        }
        return null;
    }

    @Override
	public void onFragment( WebSocket conn, Framedata fragment ) {
		/*System.out.println( "received fragment: " + fragment );*/
	}

	public static void main( String[] args ) throws InterruptedException , IOException {
        int tempNumber = 1000;
        for (int i = 0 ; i < 100 ; i ++) {
            links.add(new Link(tempNumber));
            tempNumber--;
        }

		WebSocketImpl.DEBUG = true;
		int port = 8887; // 843 flash policy port
		try {
			port = Integer.parseInt( args[ 0 ] );
		} catch ( Exception ex ) {
		}
		ChatServer s = new ChatServer( port );
		s.start();
		System.out.println( "ChatServer started on port: " + s.getPort() );
        outTheExplain();
        BufferedReader sysin = new BufferedReader( new InputStreamReader( System.in ) );
		while ( true ) {
			String in = sysin.readLine();
            if (!in.equals("")){
                s.sendToAll("wake");
                if (in.equals("o")) {
                    s.sendToAll( "open_camera" );
                } else if (in.equals("s")) {
                    s.sendToAll( "start_" + (System.currentTimeMillis() + 5000) );
                } else if (in.equals("t")) {
                    s.sendToAll( "stop_" + (System.currentTimeMillis() + 5000) );
                } else if (in.equals("h")) {
                    s.sendToAll( "home" );
                } else if (in.equals("w")) {
                    s.sendToAll("wake");
                }
                outTheExplain();
            }

			if( in.equals( "exit" ) ) {
				s.stop();
				break;
			} else if( in.equals( "restart" ) ) {
				s.stop();
				s.start();
				break;
			}
		}
	}

    private static void outTheExplain() {
        System.out.println(" 命令说明：\r\n" +
                " o:打开camera \r\n" +
                " s:五秒后开始录像 \r\n" +
                " t:五秒后停止 \r\n" +
                " h:退出相机，等待手机休眠以便节省电量 \r\n" +
                " 手机被控制后请不要手动操作手机。\r\n" + getUnLinks());
    }

    @Override
	public void onError( WebSocket conn, Exception ex ) {
		ex.printStackTrace();
		if( conn != null ) {
			// some errors like port binding failed may not be assignable to a specific websocket
		}
	}

	/**
	 * Sends <var>text</var> to all currently connected WebSocket clients.
	 * 
	 * @param text
	 *            The String to send across the network.
	 * @throws InterruptedException
	 *             When socket related I/O errors occur.
	 */
	public void sendToAll( String text ) {
		Collection<WebSocket> con = connections();
		synchronized ( con ) {
			for( WebSocket c : con ) {
				c.send( text );
			}
		}
	}
}
